﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using CustomControl;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TeacherLeftHand.DataAccess;
using TeacherLeftHand.Messages;
using TeacherLeftHand.Model;
using TeacherLeftHand.Util;
using TeacherLeftHand.View;

namespace TeacherLeftHand.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class CreateNewTMViewModel : ViewModelBase, IDataErrorInfo
    {
        /// <summary>
        /// Initializes a new instance of the CreateNewTMViewModel class.
        /// </summary>
        public CreateNewTMViewModel()
        {
            _subjectList = new SelectionList<string>(_kiAccessor.GetSubjectList());

           
            // register
            Messenger.Default.Register<CreateNewTMWindowMessage>(this, msg =>
                                                                            {
                                                                                SubjectList.UnselectAll();
                                                                                switch (msg.Action)
                                                                                {
                                                                                    case WindowAction.OpenCreate:
                                                                                        _action = UpdateAction.Add;
                                                                                        _tm = new TeachingMethod();
                                                                                        Title =
                                                                                            DataHelper.CreateNewTMTitle;
                                                                                        Messenger.Default.Send(new NewWindowMessage
                                                                                        {
                                                                                            Action = WindowAction.OpenCreate,
                                                                                            ItemType = _tm
                                                                                        });
                                                                                        break;
                                                                                    case WindowAction.OpenUpdate:
                                                                                        _action = UpdateAction.Update;
                                                                                        _tm = new TeachingMethod(msg.Item);
                                                                                        Title = DataHelper.UpdateTMTitle;
                                                                                        if (_tm.PreferredSubject != null)
                                                                                        {
                                                                                            foreach (var subject in _subjectList)
                                                                                            {
                                                                                                subject.IsSelected = _tm.PreferredSubject.Contains(subject.Item);
                                                                                            }
                                                                                        }
                                                                                        Messenger.Default.Send(new NewWindowMessage
                                                                                        {
                                                                                            Action = WindowAction.OpenUpdate,
                                                                                            ItemType = _tm
                                                                                        });
                                                                                        break;
                                                                                }
                                                                            });

        }

        private UpdateAction _action = UpdateAction.Add;
        private TeachingMethod _tm = new TeachingMethod();
        private readonly TeachingMethodAccessor _tmAccessor = new TeachingMethodAccessor();
        private readonly KnowledgeItemAccessor _kiAccessor = new KnowledgeItemAccessor();

        /// <summary>
        /// The <see cref="CanSave" /> property's name.
        /// </summary>
        public const string CanSavePropertyName = "CanSave";

        private bool _canSave;

        /// <summary>
        /// Gets the CanSave property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool CanSave
        {
            get
            {
                return _canSave;
            }
            set
            {
                if (_canSave == value) return;

                _canSave = value;
                RaisePropertyChanged(CanSavePropertyName);
            }
         }

        /// <summary>
        /// The <see cref="Title" /> property's name.
        /// </summary>
        public const string TitlePropertyName = "Title";

        private string _title = DataHelper.CreateNewTMTitle;

        /// <summary>
        /// Gets the Title property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string Title
        {
            get
            {
                return _title;
            }

            set
            {
                if (_title == value)
                {
                    return;
                }
                _title = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(TitlePropertyName);
            }
        }

        public ObservableCollection<int> ClassLevelList
        {
            get { return DataHelper.ClassLevelList; }
        }

        /// <summary>
        /// The <see cref="Name" /> property's name.
        /// </summary>
        public const string NamePropertyName = "Name";

        /// <summary>
        /// Gets the Name property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string Name
        {
            get
            {
                return _tm.Name;
            }

            set
            {
                if (_tm.Name == value)
                {
                    return;
                }

                _tm.Name = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(NamePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="Content" /> property's name.
        /// </summary>
        public const string ContentPropertyName = "Content";


        /// <summary>
        /// Gets the Content property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string Content
        {
            get
            {
                return _tm.Content;
            }

            set
            {
                if (_tm.Content == value)
                {
                    return;
                }

                _tm.Content = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(ContentPropertyName);
            }
        }

        private ICommand _createKIHolder;
        public ICommand CreateKIHolderCommand
        {
            get
            {
                if (_createKIHolder == null)
                {
                    _createKIHolder = 
                        new RelayCommand<RichTextEditor>(
                                  rtbContent =>
                                            {
                                                rtbContent.Focus();
                                                var caretPos = rtbContent.CaretPosition;
                                                var newInlineRtb = new InlineRichTextBox
                                                                    {
                                                                        MinWidth = 50,
                                                                        IsReadOnly = true,
                                                                        HorizontalAlignment = 
                                                                            HorizontalAlignment.Stretch,
                                                                        Focusable = false,
                                                                        Background = Brushes.LightBlue
                                                                    };
                                                var container = new InlineUIContainer
                                                    (newInlineRtb,
                                                    caretPos)
                                                                    {
                                                                        BaselineAlignment
                                                                            = BaselineAlignment.Center
                                                                    };
                                                // Set the TextPointer to the end of the current document.
                                                var moveTo =
                                                    rtbContent.CaretPosition.
                                                        GetNextInsertionPosition(
                                                            LogicalDirection.
                                                                Forward);

                                                if (moveTo != null)
                                                {
                                                    rtbContent.CaretPosition =
                                                        moveTo;
                                                }

                                            });
                }
                return _createKIHolder;
            }
            
        }

        /// <summary>
        /// The <see cref="PreferredClassLevel" /> property's name.
        /// </summary>
        public const string PreferredClassLevelPropertyName = "PreferredClassLevel";

        /// <summary>
        /// Gets the PreferredClassLevel property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public int PreferredClassLevel
        {
            get
            {
                return _tm.PreferredClassLevel;
            }

            set
            {
                if (_tm.PreferredClassLevel == value)
                {
                    return;
                }

                _tm.PreferredClassLevel = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(PreferredClassLevelPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SubjectList" /> property's name.
        /// </summary>
        public const string SubjectListPropertyName = "SubjectList";

        private SelectionList<string> _subjectList = new SelectionList<string>();

        /// <summary>
        /// Gets the SubjectList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public SelectionList<string> SubjectList
        {
            get
            {
                //if (PreferredSubject != null)
                //{
                //    foreach (var subject in _subjectList)
                //    {
                //        subject.IsSelected = PreferredSubject.Contains(subject.Item);
                //    }
                //}
                return _subjectList;
            }
            set
            {
                _subjectList = value;

                RaisePropertyChanged(SubjectListPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="PreferredSubject" /> property's name.
        /// </summary>
        public const string PreferredSubjectPropertyName = "PreferredSubject";

        /// <summary>
        /// Gets the PreferredSubject property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<string> PreferredSubject
        {
            get
            {
                if (_tm.PreferredSubject == null)
                {
                    return new ObservableCollection<string>();
                }
                return new ObservableCollection<string>(_tm.PreferredSubject);
            }
            set
            {
                var valueList = new List<string>(value);
                if (_tm.PreferredSubject != valueList)
                {
                    _tm.PreferredSubject = valueList;
                    RaisePropertyChanged(PreferredSubjectPropertyName);
                }
            }
        }

        /// <summary>
        /// The <see cref="Note" /> property's name.
        /// </summary>
        public const string NotePropertyName = "Note";

        /// <summary>
        /// Gets the Note property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public string Note
        {
            get
            {
                return _tm.Note;
            }

            set
            {
                if (_tm.Note == value)
                {
                    return;
                }

                _tm.Note = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(NotePropertyName);
            }
        }

        private RelayCommand<RichTextEditor> _saveCommand;
        public RelayCommand<RichTextEditor> SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand<RichTextEditor>(rtbContent =>
                    {
                        //clear Context Menu before save
                        ProcessBeforeSaving(rtbContent);
                        _tm.Content = XamlWriter.Save(rtbContent);
                        if (_action.Equals(UpdateAction.Add))
                        {
                            _tm.ID = Add();
                            if (_tm.ID > 0)
                            {
                                var msg = new UpdateTMMessage
                                {
                                    Action = _action,
                                    TeachingMethod = _tm
                                };
                                Messenger.Default.Send(msg);
                                Messenger.Default.Send(new CloseWindowMessage());
                            }
                        }
                        else
                        {
                            if (Save())
                            {
                                var msg = new UpdateTMMessage
                                {
                                    Action = _action,
                                    TeachingMethod = _tm
                                };
                                Messenger.Default.Send(msg);
                                Messenger.Default.Send(new CloseWindowMessage());

                            }
                        }
                    });
                }
                return _saveCommand;
            }
            
        }

        public ICommand CancelCommand
        {
            get;
            private set;
        }

       
        #region methods
        private bool Save()
        {
            if (_tm.PreferredSubject == null) _tm.PreferredSubject = new List<string>();
            foreach (var selectionItem in SubjectList)
            {
                if (selectionItem.IsSelected)
                {
                    if (!_tm.PreferredSubject.Contains(selectionItem.Item))
                    {
                        _tm.PreferredSubject.Add(selectionItem.Item);
                    }
                }
                else
                {
                    if (_tm.PreferredSubject.Contains(selectionItem.Item))
                    {
                        _tm.PreferredSubject.Remove(selectionItem.Item);
                    }
                }

            }
            return _tmAccessor.Update(_tm);
        }

        private int Add()
        {
            if (_tm.PreferredSubject == null) _tm.PreferredSubject = new List<string>();
            foreach (var selectionItem in SubjectList)
            {
                if (selectionItem.IsSelected)
                {
                    if (!_tm.PreferredSubject.Contains(selectionItem.Item))
                    {
                        _tm.PreferredSubject.Add(selectionItem.Item);
                    }
                }
                else
                {
                    if (_tm.PreferredSubject.Contains(selectionItem.Item))
                    {
                        _tm.PreferredSubject.Remove(selectionItem.Item);
                    }
                }

            }
            return _tmAccessor.Add(_tm);
        }

        #endregion
        ////public override void Cleanup()
        ////{
        ////    // Clean own resources if needed

        ////    base.Cleanup();
        ////}
        private static void ProcessBeforeSaving(RichTextEditor richTextEditor)
        {
            //richTextEditor.ClearValue(RichTextEditor.ContextMenuProperty);
            //foreach (Block b in richTextEditor.Document.Blocks)
            //{
            //    if (b is Paragraph)
            //    {
            //        foreach (Inline i in ((Paragraph)b).Inlines)
            //        {
            //            var inlineType = i.GetType();

            //            if (inlineType == typeof(InlineUIContainer))
            //            {
            //                //The inline has an object, likely an IMAGE!!!
            //                var uic = ((InlineUIContainer)i);

            //                if (uic.Child.GetType() == typeof(InlineRichTextBox))
            //                {
            //                    var temp = (InlineRichTextBox)uic.Child;
            //                    temp.ClearValue(RichTextEditor.ContextMenuProperty);
            //                }
            //            }
            //            if(inlineType == typeof(Span))
            //            {
            //                foreach (var ninline in ((Span)i).Inlines)
            //                {
            //                    if (ninline is InlineUIContainer)
            //                    {
            //                        var child = ((InlineUIContainer) ninline).Child;
            //                        if(child is InlineRichTextBox)
            //                        {
            //                            var temp = (InlineRichTextBox)child;
            //                            temp.ClearValue(RichTextEditor.ContextMenuProperty);
            //                        }
            //                    }
            //                }
            //            }
            //        }
                    
            //    }
            //}
            richTextEditor.ClearValue(RichTextEditor.ContextMenuProperty);
            foreach (var block in richTextEditor.Document.Blocks)
            {
                Utility.ProcessBeforeSaving(block);
            }
            
        }


       
        #region Implementation of IDataErrorInfo

        /// <summary>
        /// Gets the error message for the property with the given name.
        /// </summary>
        /// <returns>
        /// The error message for the property. The default is an empty string ("").
        /// </returns>
        /// <param name="columnName">The name of the property whose error message to get. </param>
        public string this[string columnName]
        {
            get
            {
                var msg = "";
                switch (columnName)
                {
                    case NamePropertyName:
                        if (string.IsNullOrEmpty(Name))
                        {
                            msg = TranslationManager.Instance.Translate(DataHelper.TMRequiredNameMsg).ToString();
                        }
                        break;
                    
                    default:
                        msg = string.Empty;
                        break;
                }
                CanSave = string.IsNullOrEmpty(msg);
                return msg;
            }
        }

        /// <summary>
        /// Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <returns>
        /// An error message indicating what is wrong with this object. The default is an empty string ("").
        /// </returns>
        public string Error
        {
            get { return null; }
        }

        
        #endregion
    }
}